package fem2.pre_and_post;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.StringTokenizer;

import fem2.MeshGenerator;

public class GidMeshGenerator extends MeshGenerator {

	private static final String INITIAL_BLOCK_KEYWORD = "MESH";
	private static final String NUMNODE_KEYWORD = "Nnode";
	private static final String ELEMENT_HEADER_START = "Elements";
	private static final String ELEMENT_HEADER_END_1 = "end elements";
	private static final String ELEMENT_HEADER_END_2 = "End Elements";
	private static final String COORDINATES_HEADER_START = "Coordinates";
	private static final String COORDINATES_HEADER_END_1 = "end coordinates";
	private static final String COORDINATES_HEADER_END_2 = "End Coordinates";
	private static final int ELEMENT_BASE_INDEX = 1;

	private File file;

	public GidMeshGenerator(String fileName) {
		file = new File(fileName);
	}

	@Override
	public ArrayList<double[]> getNodes(int dim) {
		ArrayList<double[]> nodes = new ArrayList<double[]>();
		Scanner scanner = null;
		try {
			scanner = new Scanner(new FileReader(file));
		} catch (FileNotFoundException e) {
			throw new Error("File not found: " + e.getMessage());
		}
		try {
			boolean isBlock = false;
			boolean startRead = false;
			while (scanner.hasNextLine()) {
				String line = scanner.nextLine();
				/*
				 * if meet the empty line, then skip
				 */
				if (line.compareTo("") == 0) {
					continue;
				}
				StringTokenizer s = new StringTokenizer(line);
				/*
				 * check if current position fall in a block
				 */
				if (!isBlock) {
					/*
					 * search for keyword MESH
					 */
					if (s.nextToken().compareTo(INITIAL_BLOCK_KEYWORD) == 0) {
						isBlock = true;
					}
				} else {
					if (!startRead) {
						/*
						 * search for keyword Coordinates
						 */
						if (line.compareTo(COORDINATES_HEADER_START) == 0) {
							startRead = true;
						}
					} else {
						if (line.compareTo(COORDINATES_HEADER_END_1) == 0
								|| line.compareTo(COORDINATES_HEADER_END_2) == 0) {
							startRead = false;
							isBlock = false;
						} else {
							/*
							 * skip the index
							 */
							s.nextToken();
							/*
							 * read node data
							 */
							double[] v = new double[dim];
							for (int i = 0; i < dim; i++) {
								v[i] = Double.parseDouble(s.nextToken());
							}
							nodes.add(v);
						}
					}
				}
			}
		} finally {
			/*
			 * close the line scanner
			 */
			scanner.close();
		}
		return nodes;
	}

	@Override
	public ArrayList<ArrayList<Integer>> getConnectivities() {
		ArrayList<ArrayList<Integer>> connectivities = new ArrayList<ArrayList<Integer>>();
		Scanner scanner = null;
		try {
			scanner = new Scanner(new FileReader(file));
		} catch (FileNotFoundException e) {
			throw new Error("File not found: " + e.getMessage());
		}
		try {
			boolean isBlock = false;
			boolean startRead = false;
			int nnode = 0;
			while (scanner.hasNextLine()) {
				String line = scanner.nextLine();
				/*
				 * if meet the empty line, then skip
				 */
				if (line.compareTo("") == 0) {
					continue;
				}
				StringTokenizer s = new StringTokenizer(line);
				/*
				 * check if current position fall in a block
				 */
				if (!isBlock) {
					/*
					 * search for keyword MESH
					 */
					if (s.nextToken().compareTo(INITIAL_BLOCK_KEYWORD) == 0) {
						isBlock = true;
						/*
						 * read the number of nodes in current block
						 */
						while (s.hasMoreTokens()) {
							if (s.nextToken().compareTo(NUMNODE_KEYWORD) == 0) {
								nnode = Integer.parseInt(s.nextToken());
							}
						}
						if (nnode == 0) {
							throw new Error("number of nodes is zero");
						}
					}
				} else {
					if (!startRead) {
						/*
						 * search for keyword Coordinates
						 */
						if (line.compareTo(ELEMENT_HEADER_START) == 0) {
							startRead = true;
						}
					} else {
						if (line.compareTo(ELEMENT_HEADER_END_1) == 0
								|| line.compareTo(ELEMENT_HEADER_END_2) == 0) {
							startRead = false;
							isBlock = false;
						} else {
							/*
							 * skip the index
							 */
							s.nextToken();
							/*
							 * read node data
							 */
							ArrayList<Integer> e = new ArrayList<Integer>();
							for (int i = 0; i < nnode; i++) {
								e.add(Integer.parseInt(s.nextToken()) - ELEMENT_BASE_INDEX);
							}
							connectivities.add(e);
						}
					}
				}
			}
		} finally {
			/*
			 * close the line scanner
			 */
			scanner.close();
		}
		return connectivities;
	}

}
